package com.example.ordersystem.controller;


import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.example.ordersystem.config.AlipayConfig;
import com.example.ordersystem.domain.*;
import com.example.ordersystem.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Controller
@RequestMapping("/customer")
public class CustomerController {
    /**
     * 地球半径,单位 km
     */
    private static final double EARTH_RADIUS = 6378.137;

    @Autowired
    CategoryService categoryService;

    @Autowired
    CustomerService customerService;

    @Autowired
    DishService dishService;

    @Autowired
    CommentService commentService;

    @Autowired
    OrderService orderService;

    @Autowired
    LineitemService lineitemService;

    @Autowired
    MerchantService merchantService;

    /**
     * 显示顾客主页
     *
     * @param request request请求
     * @return 主页页面
     */
    @RequestMapping("/homePage")
    public String homePage(HttpServletRequest request) {
        request.setAttribute("categories", categoryService.findAllCategories());
        return "/customers/homePage";
    }

    /**
     * 用户地址设置
     *
     * @param request
     * @return 地址设置页面
     */
    @RequestMapping("/addressPage")
    public String addressPage(HttpServletRequest request){
        //把用户地址以参数形式传过来

        return "/customers/address";
    }

    /**
     * 选择门店页面
     * @param request
     * @return
     */
    @RequestMapping("/optroomPage")
    public String optroomPage(HttpServletRequest request){
        request.setAttribute("roomaddress",merchantService.findAllRoom());
        return "/customers/optroom";
    }

    /**
     * 选择门店
     * @param request
     * @param roomAddress
     * @return
     */
    @RequestMapping("/optroom")
    public String optroom(HttpServletRequest request,String roomAddress){
        request.setAttribute("categories", categoryService.findAllCategories());
        request.getSession().setAttribute("merchantaddress",roomAddress);
        request.setAttribute("optsuccess","选择成功");
        return "forward:/customer/welcome";
    }

    /**
     * 欢迎页面
     * @param request
     * @return
     */
    @RequestMapping("/welcome")
    public String welcome(HttpServletRequest request){
        return "/customers/welcome";
    }

    /**
     * 保存收货地址
     * 配送费的计算
     * @param request
     * @param address
     * @return
     */
    @RequestMapping("/customeraddress")
    public String customeraddress(HttpServletRequest request,String address,String lng,String lat){
        request.getSession().setAttribute("customeraddress",address);
        System.out.println(address+"customeraddress,customeraddress,customeraddress");
        System.out.println(lng+"lng;lng;lng;lng;lng;lng;");
        String merchantaddress = request.getSession().getAttribute("merchantaddress").toString();
        System.out.println(merchantaddress+"+++++++++++++++++++++");
        RoomAddress roomAddress = merchantService.findRoomByName(merchantaddress);
        double distance = getDistance(Double.parseDouble(lng),Double.parseDouble(lat),Double.parseDouble(roomAddress.getLng()),Double.parseDouble(roomAddress.getLat()));
        double distancebill = distance;
        System.out.println(distance+"+++++++++++++++++++++");
        request.setAttribute("distancebill",distancebill);
        return "/customers/lineitems";
    }

    /**
     * 根据经纬度，计算两点间的距离
     *
     * @param longitude1 第一个点的经度
     * @param latitude1  第一个点的纬度
     * @param longitude2 第二个点的经度
     * @param latitude2  第二个点的纬度
     * @return 返回距离 单位千米
     */
    public static double getDistance(double longitude1, double latitude1, double longitude2, double latitude2) {
        // 纬度
        double lat1 = Math.toRadians(latitude1);
        double lat2 = Math.toRadians(latitude2);
        // 经度
        double lng1 = Math.toRadians(longitude1);
        double lng2 = Math.toRadians(longitude2);
        // 纬度之差
        double a = lat1 - lat2;
        // 经度之差
        double b = lng1 - lng2;
        // 计算两点距离的公式
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
        // 弧长乘地球半径, 返回单位: 千米
        s =  s * EARTH_RADIUS;
        return s;
    }

    /**
     * 顾客查看自己所有的订单
     *
     * @return jsp页面
     */
    @RequestMapping("/ordersPage")
    public String ordersPage(HttpServletRequest request) {
        request.setAttribute("orders", orderService.findByCustomer(getCustomerNum(request)));
        return "/customers/orders";
    }


    /**
     * 顾客查看订单详情
     *
     * @param orderNum 订单编号
     * @param request  请求
     * @return 在jsp页面显示订单详情
     */
    @RequestMapping("orderDetail")
    public String orderDetail(String orderNum, HttpServletRequest request) {
        request.setAttribute("orderDetail", lineitemService.selectByOrderNum(orderNum));
        return "/customers/orderDetail";
    }

    /**
     * 个人信息页面
     *
     * @return jsp页面
     */
    @RequestMapping("/personal")
    public String personal(){
        return "/customers/personal";
    }

    /**
     * 修改密码页面
     *
     * @return jsp页面
     */
    @RequestMapping("/modifyPassPage")
    public String modifyPassPage() {
        return "/customers/modifyPass";
    }

    /**
     * 修改密码
     *
     * @param mpass   原密码
     * @param newpass 新密码
     * @return
     */
    @RequestMapping("/modifyPass")
    public String modifyPass(HttpServletRequest request, String mpass, String newpass) {
        /*当前顾客信息*/
        Customer customer = (Customer) request.getSession().getAttribute("customer");
        /*判断原始密码是否正确*/
        if (customer.getPwd().equals(mpass)) {
            /*修改密码*/
            customerService.modifyPass(customer.getNum(), newpass);
            /*更新当前顾客信息*/
            customer.setPwd(newpass);
            request.setAttribute("modifySuccess", "密码修改成功");
        } else {
            request.setAttribute("originalPwdError", "原始密码不正确");
        }
        return "forward:/customer/modifyPassPage";
    }


    /**
     * 根据菜品分类编号,显示某一类菜品
     *
     * @param request     请求
     * @param categoryNum 分类编号
     * @return 分类编号对应的菜品页面
     */
    @RequestMapping("/dish")
    public String dish(HttpServletRequest request, String categoryNum) {
        request.setAttribute("dishes", dishService.findByCategoryNum(categoryNum));
        System.out.println("********************");
        System.out.println("categoryNum:" + categoryNum);
        System.out.println("********************");
        return "/customers/dish";
    }

    /**
     * 查看店铺评价
     *
     * @return 评价页面
     */
    @RequestMapping("/comments")
    public String comments(HttpServletRequest request) {
        request.setAttribute("comments", commentService.findAllComments());
        return "/customers/comments";
    }

    /**
     * 显示已选菜品的页面
     */
    @RequestMapping(value = "/lineitems")
    public String lineitems() {
        return "/customers/lineitems";
    }

    /**
     * 顾客还没有选择任何菜品
     */
    @RequestMapping(value = "/nothing")
    public String nothing() {
        return "/customers/nothing";
    }

    /**
     * 在订单中添加或者更新一个菜品项
     *
     * @param request  http请求
     * @param quantity 数量
     * @param num      菜品编号
     * @param name     菜品名称
     * @param price    菜品单价
     * @param picture  菜品图片
     */
    @RequestMapping("/addDishitem")
    @SuppressWarnings(value = "unchecked")
    public void addDishitem(HttpServletRequest request
            , String quantity, String num, String name
            , String price, String picture) {
        /*订购数量*/
        int quan = Integer.parseInt(quantity);

        /*菜品编号*/
        int n = Integer.parseInt(num);

        /*菜品单价*/
        int p = Integer.parseInt(price);

        /*新的菜品项*/
        LineitemInfo item = new LineitemInfo(n, name, picture, p, quan);

        Object itemsObj = request.getSession().getAttribute("items");
        List<LineitemInfo> items;
        if (itemsObj == null) {
            items = new ArrayList<>();
        } else {
            items = (List<LineitemInfo>) itemsObj;
            /*是用户已经订购过的菜品,需要更新订购数量*/
            if (items.contains(item)) {
                items.remove(item);
                item.setQuantity(quan);
            }
        }
        /*添加菜品*/
        items.add(item);
        request.getSession().setAttribute("items", items);
        //log.debug(quantity);
    }

    /**
     * 删除一个订单项
     *
     * @param request 请求
     * @return 订单项页面
     */
    @RequestMapping("/deleteDishitem")
    @SuppressWarnings("unchecked")
    public String deleteDishitem(HttpServletRequest request) {

        /*获取当前顾客的所有菜单项*/
        List<LineitemInfo> items = (List<LineitemInfo>) request.getSession().getAttribute("items");
        /*获取待删除的订单项下标*/
        int index = Integer.parseInt(request.getParameter("index"));
        items.remove(index);
        request.getSession().setAttribute("items", items);
        return "forward:/customer/lineitems";
    }

    /**
     * 结账页面
     *
     * @return jsp页面
     */
    @RequestMapping("/checkoutPage")
    public String checkoutPage() {
        return "/customers/checkout";
    }

    /**
     * 支付宝沙箱页面支付,下单后支付
     *
     * @param remark 顾客备注
     * @return 支付宝返回的form页面
     */
    @RequestMapping("/pay")
    @ResponseBody
    public String payPage(HttpServletRequest request, String remark, String customeraddress) throws AlipayApiException {

        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(AlipayConfig.return_url);

        //商户订单号，商户网站订单系统中唯一订单号，必填
        String out_trade_no = request.getParameter("WIDout_trade_no");

        /*放入session中是为了查询本次交易*/
        request.getSession().setAttribute("out_trade_no", out_trade_no);

        //付款金额，必填
        String total_amount = request.getParameter("WIDtotal_amount");

        //订单名称，必填
        String subject = request.getParameter("WIDsubject");

        //商品描述，可空
        String body = "";

        alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no + "\","
                + "\"total_amount\":\"" + total_amount + "\","
                + "\"subject\":\"" + subject + "\","
                + "\"body\":\"" + body + "\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        /*支付请求*/
        String result = alipayClient.pageExecute(alipayRequest).getBody();
        Order order = new Order();
        order.setNum(out_trade_no);
        order.setTotal(Integer.parseInt(total_amount));
        order.setCustomer(getCustomerNum(request));
        order.setCustomeraddress(customeraddress);
        order.setRemark(remark);
        order.setBirth(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        /*放入session中以便后续插入数据库中*/
        request.getSession().setAttribute("order", order);
        return result;
    }

    /**
     * 支付宝沙箱支付,下单-未支付-支付
     *
     * @param orderNum 订单编号
     * @return html页面
     */
    @RequestMapping("/payOrder")
    @ResponseBody
    public String payOrder(HttpServletRequest request, String orderNum, String amount) throws AlipayApiException {

        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(AlipayConfig.return_url);

        //商户订单号，商户网站订单系统中唯一订单号，必填
        String out_trade_no = orderNum;

        //付款金额，必填
        String total_amount = amount;

        //订单名称，必填
        String subject = ((Customer) request.getSession().getAttribute("customer")).getName();

        //商品描述，可空
        String body = "";

        alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no + "\","
                + "\"total_amount\":\"" + total_amount + "\","
                + "\"subject\":\"" + subject + "\","
                + "\"body\":\"" + body + "\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        /*支付请求*/
        AlipayTradePagePayResponse response = alipayClient.pageExecute(alipayRequest);

        /*支付成功*/
        if (query(orderNum).equals(Order.SUCCESS)) {
            /*更新订单状态*/
            orderService.updateStatusByNum(orderNum, Order.TRADE_STATUS.get(Order.SUCCESS));
        }
        return response.getBody();
    }

    /**
     * 确认收货,交易完成
     *
     * @param orderNum 订单号
     * @return 交易完成后，返回所有订单页面
     */
    @RequestMapping("/confirmTrade")
    public String confirmTrade(HttpServletRequest request, String orderNum) {
        /*交易完成*/
        orderService.updateStatusByNum(orderNum, Order.TRADE_STATUS.get(Order.FINISHED));
        request.setAttribute("orderNum", orderNum);
        return "forward:/customer/addCommentPage";
    }

    /**
     * 取消订单,交易关闭
     *
     * @param orderNum 订单号
     * @return 交易关闭后，返回所有订单页面
     */
    @RequestMapping("/cancelTrade")
    public String cancelTrade(String orderNum) {
        /*删除订单*/
        orderService.deleteByNum(orderNum);
        return "forward:/customer/ordersPage";
    }

    /**
     * 申请退款
     *
     * @param orderNum 订单号
     * @return 申请完成后, 返回所有订单页面
     */
    @RequestMapping("/applyRefund")
    public String applyRefund(String orderNum) {
        /*申请退款*/
        orderService.updateStatusByNum(orderNum, Order.REFUNDING);
        return "forward:/customer/ordersPage";
    }

    private void outPut(String msg) {
        System.out.println("********************");
        System.out.println(msg);
        System.out.println("********************");
    }

    private int getCustomerNum(HttpServletRequest request) {
        Customer customer = (Customer) request.getSession().getAttribute("customer");
        return customer.getNum();
    }

    /**
     * 支付查询
     *
     * @param out_trade_no 商户订单号
     * @return 支付状态
     * @throws AlipayApiException 支付异常
     */
    private String query(String out_trade_no) throws AlipayApiException {
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        //设置请求参数
        AlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();

        //支付宝交易号
        String trade_no = "";
        //请二选一设置
        alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no + "\"," + "\"trade_no\":\"" + trade_no + "\"}");

        /*发送查询请求,并获得json格式响应数据*/
        String result = alipayClient.execute(alipayRequest).getBody();
        outPut(result);
        /*json数据转为map*/
        Map maps = (Map) JSON.parse(result);

        /*获取支付信息*/
        Object alipay_trade_query_response = maps.get("alipay_trade_query_response");
        Map info = (Map) JSON.parse(String.valueOf(alipay_trade_query_response));

        /*返回支付状态*/
        return (String) info.get("trade_status");
    }

    /**
     * 提示用户付款的页面
     *
     * @return jsp页面
     */
    @RequestMapping("/attentionPage")
    public String attentionPage() {
        return "customers/attention";
    }

    /**
     * 支付成功后,显示页面
     *
     * @return 结算成功后的页面
     */
    @RequestMapping("/billPage")
    public String billPage(HttpServletRequest request) throws AlipayApiException {

        /*获取当前订单信息*/
        Order order = (Order) request.getSession().getAttribute("order");

        /*获取支付状态*/
        String status = query(order.getNum());

        /*设置订单状态*/
        order.setStatus(Order.TRADE_STATUS.get(status));

        /*将订单及支付状态写入数据库中*/
        orderService.addOrder(order);

        /*将各订单项写入数据库*/
        insertLineitems(request, order.getNum());

        /*支付后,删除会话中,顾客选择的菜品*/
        request.getSession().removeAttribute("items");

        return "customers/bill";
    }

    /**
     * 向数据库中插入
     *
     * @param request  请求
     * @param orderNum 订单号
     */
    private void insertLineitems(HttpServletRequest request, String orderNum) {
        @SuppressWarnings("unchecked")
        List<LineitemInfo> items = (List<LineitemInfo>) request.getSession().getAttribute("items");

        for (LineitemInfo item : items) {
            Lineitem lineitem = new Lineitem();
            lineitem.setOrderNum(orderNum);
            lineitem.setDishNum(item.getdNum());
            lineitem.setDishPrice(item.getPrice());
            lineitem.setQuantity(item.getQuantity());
            lineitem.setAmount(item.getPrice() * item.getQuantity());
            lineitemService.addLineitem(lineitem);
        }
    }

    /**
     * 评价订单的页面
     *
     * @return 评价发布后，返回所有评价页面
     */
    @RequestMapping("/addCommentPage")
    public String addCommentPage() {
        return "/customers/addComment";
    }


    /**
     * 上传图片
     *
     * @param file     待上传的文件
     * @param request  请求
     * @param fileName 新的文件名
     * @throws IOException 写文件异常
     */
    private void upload(MultipartFile file, HttpServletRequest request, String fileName) throws IOException {
        /*获取项目运行时,评论中图片的存储路径*/
        String realPath = request.getServletContext().getRealPath(Comment.PATH);
        File destFile = new File(realPath, Objects.requireNonNull(fileName));
        /*保存图片*/
        file.transferTo(destFile);
    }

    /**
     * 用户确认收货后,对一个订单进行评价
     *
     * @param request  请求
     * @param orderNum 订单号
     * @param number   评价等级
     * @param content  评价内容
     * @param choose   是否配图;当取值为'yes'时,代表选择了配图;当取值为'no'时,说明顾客没有选择配图
     * @param file     选择的文件
     * @return 评价完成后, 返回店铺所有评价页面
     */
    @RequestMapping("/addComment")
    public String addComment(HttpServletRequest request, MultipartFile file, String orderNum, String number, String content, String choose) throws IOException {

        outPut(file.getOriginalFilename());

        /*获取checkbox所有的选中值*/
        String[] label = request.getParameterValues("label");
        for (String name : label) {
            /*在数据库中跟新标签出现的次数**/
            commentService.updateLabelByName(name);
        }
        /*插入一条评论,并返回评论的编号*/
        int commentNum = commentService.addComment(orderNum, getCustomerNum(request)
                , Integer.parseInt(number), content);

        if ("yes".equals(choose)) {
            /*上传的文件名*/
            String uploadFileName = file.getOriginalFilename();
            /*文件后缀*/
            String suffix = uploadFileName.substring(uploadFileName.lastIndexOf("."));
            /*对上传的图片进行重命名*/
            String fileName = String.valueOf(commentNum).concat(suffix);
            /*上传图片*/
            upload(file, request, fileName);
            /*更新数据库中评论的文件名*/
            commentService.updatePictureByNum(commentNum, fileName);
        }
        return "redirect:/customer/commentsPage";
    }

    /**
     * 从数据库中查询所有评价,评价标签
     *
     * @return 带着所有评价的页面
     */
    @RequestMapping("commentsPage")
    public String commentsPage(HttpServletRequest request) {
        request.setAttribute("comments", commentService.findAllComments());
        request.setAttribute("labels", commentService.findAllLabels());
        /*平均评分*/
        request.setAttribute("average",commentService.selectAverageGrade());
        return "/customers/comments";
    }
}
